[XSM] correctly rename, relocate and patch the security.py file
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 6 Sep 2007 17:05:18 +0000 (18:05 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 6 Sep 2007 17:05:18 +0000 (18:05 +0100)
This patch corrects an error in the original XSM tools patch.  The
original patch did not rename, relocate and patch the security.py file
from changeset 15730:256160ff19b7.  This patch addresses this issue as
well as any updates made to security.py in xen-staging during the
merge of XSM.

Signed-off-by: George Coker <gscoker@alpha.ncsc.mil>
tools/python/xen/util/security.py [deleted file]
tools/python/xen/util/xsm/acm/acm.py

diff --git a/tools/python/xen/util/security.py b/tools/python/xen/util/security.py
deleted file mode 100644 (file)
index 16cd741..0000000
+++ /dev/null
@@ -1,1301 +0,0 @@
-#===========================================================================
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of version 2.1 of the GNU Lesser General Public
-# License as published by the Free Software Foundation.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#============================================================================
-# Copyright (C) 2006 International Business Machines Corp.
-# Author: Reiner Sailer
-# Author: Bryan D. Payne <bdpayne@us.ibm.com>
-# Author: Stefan Berger <stefanb@us.ibm.com>
-#============================================================================
-
-import commands
-import logging
-import os, string, re
-import threading
-import struct
-import stat
-from xen.lowlevel import acm
-from xen.xend import sxp
-from xen.xend import XendConstants
-from xen.xend.XendLogging import log
-from xen.xend.XendError import VmError
-from xen.util import dictio, xsconstants
-from xen.xend.XendConstants import *
-
-#global directories and tools for security management
-policy_dir_prefix = "/etc/xen/acm-security/policies"
-res_label_filename = policy_dir_prefix + "/resource_labels"
-boot_filename = "/boot/grub/menu.lst"
-altboot_filename = "/boot/grub/grub.conf"
-xensec_xml2bin = "/usr/sbin/xensec_xml2bin"
-xensec_tool = "/usr/sbin/xensec_tool"
-
-#global patterns for map file
-#police_reference_tagname = "POLICYREFERENCENAME"
-primary_entry_re = re.compile("\s*PRIMARY\s+.*", re.IGNORECASE)
-secondary_entry_re = re.compile("\s*SECONDARY\s+.*", re.IGNORECASE)
-label_template_re =  re.compile(".*security_label_template.xml", re.IGNORECASE)
-mapping_filename_re = re.compile(".*\.map", re.IGNORECASE)
-policy_reference_entry_re = re.compile("\s*POLICYREFERENCENAME\s+.*", re.IGNORECASE)
-vm_label_re = re.compile("\s*LABEL->SSID\s+VM\s+.*", re.IGNORECASE)
-res_label_re = re.compile("\s*LABEL->SSID\s+RES\s+.*", re.IGNORECASE)
-all_label_re = re.compile("\s*LABEL->SSID\s+.*", re.IGNORECASE)
-access_control_re = re.compile("\s*access_control\s*=", re.IGNORECASE)
-
-#global patterns for boot configuration file
-xen_title_re = re.compile("\s*title\s+XEN", re.IGNORECASE)
-any_title_re = re.compile("\s*title\s", re.IGNORECASE)
-xen_kernel_re = re.compile("\s*kernel.*xen.*\.gz", re.IGNORECASE)
-kernel_ver_re = re.compile("\s*module.*vmlinuz", re.IGNORECASE)
-any_module_re = re.compile("\s*module\s", re.IGNORECASE)
-empty_line_re = re.compile("^\s*$")
-binary_name_re = re.compile(".*[chwall|ste|chwall_ste].*\.bin", re.IGNORECASE)
-policy_name_re = re.compile(".*[chwall|ste|chwall_ste].*", re.IGNORECASE)
-
-#decision hooks known to the hypervisor
-ACMHOOK_sharing = 1
-ACMHOOK_authorization = 2
-
-#other global variables
-NULL_SSIDREF = 0
-
-#general Rlock for map files; only one lock for all mapfiles
-__mapfile_lock = threading.RLock()
-__resfile_lock = threading.RLock()
-
-log = logging.getLogger("xend.util.security")
-
-# Our own exception definition. It is masked (pass) if raised and
-# whoever raises this exception must provide error information.
-class ACMError(Exception):
-    def __init__(self,value):
-        self.value = value
-    def __str__(self):
-        return repr(self.value)
-
-
-
-def err(msg):
-    """Raise ACM exception.
-    """
-    raise ACMError(msg)
-
-
-
-active_policy = None
-
-
-def mapfile_lock():
-    __mapfile_lock.acquire()
-
-def mapfile_unlock():
-    __mapfile_lock.release()
-
-
-def refresh_security_policy():
-    """
-    retrieves security policy
-    """
-    global active_policy
-
-    try:
-        active_policy = acm.policy()
-    except:
-        active_policy = "INACTIVE"
-
-# now set active_policy
-refresh_security_policy()
-
-def on():
-    """
-    returns none if security policy is off (not compiled),
-    any string otherwise, use it: if not security.on() ...
-    """
-    refresh_security_policy()
-    return (active_policy not in ['INACTIVE', 'NULL'])
-
-
-def calc_dom_ssidref_from_info(info):
-    """
-       Calculate a domain's ssidref from the security_label in its
-       info.
-       This function is called before the domain is started and
-       makes sure that:
-        - the type of the policy is the same as indicated in the label
-        - the name of the policy is the same as indicated in the label
-        - calculates an up-to-date ssidref for the domain
-       The latter is necessary since the domain's ssidref could have
-       changed due to changes to the policy.
-    """
-    import xen.xend.XendConfig
-    if isinstance(info, xen.xend.XendConfig.XendConfig):
-        if info.has_key('security_label'):
-            seclab = info['security_label']
-            tmp = seclab.split(":")
-            if len(tmp) != 3:
-                raise VmError("VM label '%s' in wrong format." % seclab)
-            typ, policyname, vmlabel = seclab.split(":")
-            if typ != xsconstants.ACM_POLICY_ID:
-                raise VmError("Policy type '%s' must be changed." % typ)
-            refresh_security_policy()
-            if active_policy != policyname:
-                raise VmError("Active policy '%s' different than "
-                              "what in VM's label ('%s')." %
-                              (active_policy, policyname))
-            ssidref = label2ssidref(vmlabel, policyname, "dom")
-            return ssidref
-        else:
-            return 0x0
-    raise VmError("security.calc_dom_ssidref_from_info: info of type '%s'"
-                  "not supported." % type(info))
-
-
-def getmapfile(policyname):
-    """
-    in: if policyname is None then the currently
-    active hypervisor policy is used
-    out: 1. primary policy, 2. secondary policy,
-    3. open file descriptor for mapping file, and
-    4. True if policy file is available, False otherwise
-    """
-    if not policyname:
-        policyname = active_policy
-    map_file_ok = False
-    primary = None
-    secondary = None
-    #strip last part of policy as file name part
-    policy_dir_list = string.split(policyname, ".")
-    policy_file = policy_dir_list.pop()
-    if len(policy_dir_list) > 0:
-        policy_dir = string.join(policy_dir_list, "/") + "/"
-    else:
-        policy_dir = ""
-
-    map_filename = policy_dir_prefix + "/" + policy_dir + policy_file + ".map"
-    # check if it is there, if not check if policy file is there
-    if not os.path.isfile(map_filename):
-        policy_filename =  policy_dir_prefix + "/" + policy_dir + policy_file + "-security_policy.xml"
-        if not os.path.isfile(policy_filename):
-            err("Policy file \'" + policy_filename + "\' not found.")
-        else:
-            err("Mapping file \'" + map_filename + "\' not found." +
-                " Use xm makepolicy to create it.")
-
-    f = open(map_filename)
-    for line in f:
-        if policy_reference_entry_re.match(line):
-            l = line.split()
-            if (len(l) == 2) and (l[1] == policyname):
-                map_file_ok = True
-        elif primary_entry_re.match(line):
-            l = line.split()
-            if len(l) == 2:
-                primary = l[1]
-        elif secondary_entry_re.match(line):
-            l = line.split()
-            if len(l) == 2:
-                secondary = l[1]
-    f.close()
-    f = open(map_filename)
-    if map_file_ok and primary and secondary:
-        return (primary, secondary, f, True)
-    else:
-        err("Mapping file inconsistencies found. Try makepolicy to create a new one.")
-
-
-
-def ssidref2label(ssidref_var):
-    """
-    returns labelname corresponding to ssidref;
-    maps current policy to default directory
-    to find mapping file
-    """
-    #1. translated permitted input formats
-    if isinstance(ssidref_var, str):
-        ssidref_var.strip()
-        if ssidref_var[0:2] == "0x":
-            ssidref = int(ssidref_var[2:], 16)
-        else:
-            ssidref = int(ssidref_var)
-    elif isinstance(ssidref_var, int):
-        ssidref = ssidref_var
-    else:
-        err("Instance type of ssidref not supported (must be of type 'str' or 'int')")
-
-    if ssidref == 0:
-        from xen.util.acmpolicy import ACM_LABEL_UNLABELED
-        return ACM_LABEL_UNLABELED
-
-    try:
-        mapfile_lock()
-
-        (primary, secondary, f, pol_exists) = getmapfile(None)
-        if not f:
-            if (pol_exists):
-                err("Mapping file for policy not found.\n" +
-                    "Please use makepolicy command to create mapping file!")
-            else:
-                err("Policy file for \'" + active_policy + "\' not found.")
-
-        #2. get labelnames for both ssidref parts
-        pri_ssid = ssidref & 0xffff
-        sec_ssid = ssidref >> 16
-        pri_null_ssid = NULL_SSIDREF & 0xffff
-        sec_null_ssid = NULL_SSIDREF >> 16
-        pri_labels = []
-        sec_labels = []
-        labels = []
-
-        for line in f:
-            l = line.split()
-            if (len(l) < 5) or (l[0] != "LABEL->SSID"):
-                continue
-            if primary and (l[2] == primary) and (int(l[4], 16) == pri_ssid):
-                pri_labels.append(l[3])
-            if secondary and (l[2] == secondary) and (int(l[4], 16) == sec_ssid):
-                sec_labels.append(l[3])
-        f.close()
-    finally:
-        mapfile_unlock()
-
-    #3. get the label that is in both lists (combination must be a single label)
-    if (primary == "CHWALL") and (pri_ssid == pri_null_ssid) and (sec_ssid != sec_null_ssid):
-        labels = sec_labels
-    elif (secondary == "CHWALL") and (pri_ssid != pri_null_ssid) and (sec_ssid == sec_null_ssid):
-        labels = pri_labels
-    elif secondary == "NULL":
-        labels = pri_labels
-    else:
-        for i in pri_labels:
-            for j in sec_labels:
-                if (i==j):
-                    labels.append(i)
-    if len(labels) != 1:
-        err("Label for ssidref \'" +  str(ssidref) +
-            "\' unknown or not unique in policy \'" + active_policy + "\'")
-
-    return labels[0]
-
-
-
-def label2ssidref(labelname, policyname, typ):
-    """
-    returns ssidref corresponding to labelname;
-    maps current policy to default directory
-    to find mapping file    """
-
-    if policyname in ['NULL', 'INACTIVE', 'DEFAULT']:
-        err("Cannot translate labels for \'" + policyname + "\' policy.")
-
-    allowed_types = ['ANY']
-    if typ == 'dom':
-        allowed_types.append('VM')
-    elif typ == 'res':
-        allowed_types.append('RES')
-    else:
-        err("Invalid type.  Must specify 'dom' or 'res'.")
-
-    try:
-        mapfile_lock()
-        (primary, secondary, f, pol_exists) = getmapfile(policyname)
-
-        #2. get labelnames for ssidref parts and find a common label
-        pri_ssid = []
-        sec_ssid = []
-        for line in f:
-            l = line.split()
-            if (len(l) < 5) or (l[0] != "LABEL->SSID"):
-                continue
-            if primary and (l[1] in allowed_types) and \
-                           (l[2] == primary) and \
-                           (l[3] == labelname):
-                pri_ssid.append(int(l[4], 16))
-            if secondary and (l[1] in allowed_types) and \
-                             (l[2] == secondary) and \
-                             (l[3] == labelname):
-                sec_ssid.append(int(l[4], 16))
-        f.close()
-        if (typ == 'res') and (primary == "CHWALL") and (len(pri_ssid) == 0):
-            pri_ssid.append(NULL_SSIDREF)
-        elif (typ == 'res') and (secondary == "CHWALL") and \
-             (len(sec_ssid) == 0):
-            sec_ssid.append(NULL_SSIDREF)
-
-        #3. sanity check and composition of ssidref
-        if (len(pri_ssid) == 0) or ((len(sec_ssid) == 0) and \
-            (secondary != "NULL")):
-            err("Label \'" + labelname + "\' not found.")
-        elif (len(pri_ssid) > 1) or (len(sec_ssid) > 1):
-            err("Label \'" + labelname + "\' not unique in policy (policy error)")
-        if secondary == "NULL":
-            return pri_ssid[0]
-        else:
-            return (sec_ssid[0] << 16) | pri_ssid[0]
-    finally:
-       mapfile_unlock()
-
-
-def refresh_ssidref(config):
-    """
-    looks up ssidref from security field
-    and refreshes the value if label exists
-    """
-    #called by dom0, policy could have changed after xen.utils.security was initialized
-    refresh_security_policy()
-
-    security = None
-    if isinstance(config, dict):
-        security = config['security']
-    elif isinstance(config, list):
-        security = sxp.child_value(config, 'security')
-    else:
-        err("Instance type of config parameter not supported.")
-    if not security:
-        #nothing to do (no security label attached)
-        return config
-
-    policyname = None
-    labelname = None
-    # compose new security field
-    for idx in range(0, len(security)):
-        if security[idx][0] == 'ssidref':
-            security.pop(idx)
-            break
-        elif security[idx][0] == 'access_control':
-            for jdx in [1, 2]:
-                if security[idx][jdx][0] == 'label':
-                    labelname = security[idx][jdx][1]
-                elif security[idx][jdx][0] == 'policy':
-                    policyname = security[idx][jdx][1]
-                else:
-                    err("Illegal field in access_control")
-    #verify policy is correct
-    if active_policy != policyname:
-        err("Policy \'" + str(policyname) +
-            "\' in label does not match active policy \'"
-            + str(active_policy) +"\'!")
-
-    new_ssidref = label2ssidref(labelname, policyname, 'dom')
-    if not new_ssidref:
-        err("SSIDREF refresh failed!")
-
-    security.append([ 'ssidref',str(new_ssidref)])
-    security = ['security', security ]
-
-    for idx in range(0,len(config)):
-        if config[idx][0] == 'security':
-            config.pop(idx)
-            break
-        config.append(security)
-
-
-
-def get_ssid(domain):
-    """
-    enables domains to retrieve the label / ssidref of a running domain
-    """
-    if not on():
-        err("No policy active.")
-
-    if isinstance(domain, str):
-        domain_int = int(domain)
-    elif isinstance(domain, int):
-        domain_int = domain
-    else:
-        err("Illegal parameter type.")
-    try:
-        ssid_info = acm.getssid(int(domain_int))
-    except:
-        err("Cannot determine security information.")
-
-    if active_policy in ["DEFAULT"]:
-        label = "DEFAULT"
-    else:
-        label = ssidref2label(ssid_info["ssidref"])
-    return(ssid_info["policyreference"],
-           label,
-           ssid_info["policytype"],
-           ssid_info["ssidref"])
-
-
-
-def get_decision(arg1, arg2):
-    """
-    enables domains to retrieve access control decisions from
-    the hypervisor Access Control Module.
-    IN: args format = ['domid', id] or ['ssidref', ssidref]
-    or ['access_control', ['policy', policy], ['label', label], ['type', type]]
-    """
-
-    if not on():
-        err("No policy active.")
-
-    #translate labels before calling low-level function
-    if arg1[0] == 'access_control':
-        if (arg1[1][0] != 'policy') or (arg1[2][0] != 'label') or (arg1[3][0] != 'type'):
-            err("Argument type not supported.")
-        ssidref = label2ssidref(arg1[2][1], arg1[1][1], arg1[3][1])
-        arg1 = ['ssidref', str(ssidref)]
-    if arg2[0] == 'access_control':
-        if (arg2[1][0] != 'policy') or (arg2[2][0] != 'label') or (arg2[3][0] != 'type'):
-            err("Argument type not supported.")
-        ssidref = label2ssidref(arg2[2][1], arg2[1][1], arg2[3][1])
-        arg2 = ['ssidref', str(ssidref)]
-
-    # accept only int or string types for domid and ssidref
-    if isinstance(arg1[1], int):
-        arg1[1] = str(arg1[1])
-    if isinstance(arg2[1], int):
-        arg2[1] = str(arg2[1])
-    if not isinstance(arg1[1], str) or not isinstance(arg2[1], str):
-        err("Invalid id or ssidref type, string or int required")
-
-    try:
-        decision = acm.getdecision(arg1[0], arg1[1], arg2[0], arg2[1],
-                                   ACMHOOK_sharing)
-    except:
-        err("Cannot determine decision.")
-
-    if decision:
-        return decision
-    else:
-        err("Cannot determine decision (Invalid parameter).")
-
-
-def has_authorization(ssidref):
-    """ Check if the domain with the given ssidref has authorization to
-        run on this system. To have authoriztion dom0's STE types must
-        be a superset of that of the domain's given through its ssidref.
-    """
-    rc = True
-    dom0_ssidref = int(acm.getssid(0)['ssidref'])
-    decision = acm.getdecision('ssidref', str(dom0_ssidref),
-                               'ssidref', str(ssidref),
-                               ACMHOOK_authorization)
-    if decision == "DENIED":
-        rc = False
-    return rc
-
-
-def hv_chg_policy(bin_pol, del_array, chg_array):
-    """
-        Change the binary policy in the hypervisor
-        The 'del_array' and 'chg_array' give hints about deleted ssidrefs
-        and changed ssidrefs which can be due to deleted VM labels
-        or reordered VM labels
-    """
-    rc = -xsconstants.XSERR_GENERAL_FAILURE
-    errors = ""
-    if not on():
-        err("No policy active.")
-    try:
-        rc, errors = acm.chgpolicy(bin_pol, del_array, chg_array)
-    except Exception, e:
-        pass
-    if len(errors) > 0:
-        rc = -xsconstants.XSERR_HV_OP_FAILED
-    return rc, errors
-
-
-def make_policy(policy_name):
-    policy_file = string.join(string.split(policy_name, "."), "/")
-    if not os.path.isfile(policy_dir_prefix + "/" + policy_file + "-security_policy.xml"):
-        err("Unknown policy \'" + policy_name + "\'")
-
-    (ret, output) = commands.getstatusoutput(xensec_xml2bin + " -d " + policy_dir_prefix + " " + policy_file)
-    if ret:
-        err("Creating policy failed:\n" + output)
-
-def load_policy(policy_name):
-    global active_policy
-    policy_file = policy_dir_prefix + "/" + string.join(string.split(policy_name, "."), "/")
-    if not os.path.isfile(policy_file + ".bin"):
-        if os.path.isfile(policy_file + "-security_policy.xml"):
-            err("Binary file does not exist." +
-                "Please use makepolicy to build the policy binary.")
-        else:
-            err("Unknown Policy " + policy_name)
-
-    #require this policy to be the first or the same as installed
-    if active_policy not in ['DEFAULT', policy_name]:
-        err("Active policy \'" + active_policy +
-            "\' incompatible with new policy \'" + policy_name + "\'")
-    (ret, output) = commands.getstatusoutput(xensec_tool + " loadpolicy " + policy_file + ".bin")
-    if ret:
-        err("Loading policy failed:\n" + output)
-    else:
-        # refresh active policy
-        refresh_security_policy()
-
-
-
-def dump_policy():
-    if active_policy in ['NULL', 'INACTIVE']:
-        err("\'" + active_policy + "\' policy. Nothing to dump.")
-
-    (ret, output) = commands.getstatusoutput(xensec_tool + " getpolicy")
-    if ret:
-       err("Dumping hypervisor policy failed:\n" + output)
-    print output
-
-
-
-def list_labels(policy_name, condition):
-    if (not policy_name) and (active_policy) in ["NULL", "INACTIVE", "DEFAULT"]:
-        err("Current policy \'" + active_policy + "\' has no labels defined.\n")
-
-    (primary, secondary, f, pol_exists) = getmapfile(policy_name)
-    if not f:
-        if pol_exists:
-            err("Cannot find mapfile for policy \'" + policy_name +
-                "\'.\nPlease use makepolicy to create mapping file.")
-        else:
-            err("Unknown policy \'" + policy_name + "\'")
-
-    labels = []
-    for line in f:
-        if condition.match(line):
-            label = line.split()[3]
-            if label not in labels:
-                labels.append(label)
-    return labels
-
-
-def get_res_label(resource):
-    """Returns resource label information (policytype, label, policy) if
-       it exists. Otherwise returns null label and policy.
-    """
-    def default_res_label():
-        ssidref = NULL_SSIDREF
-        if on():
-            label = ssidref2label(ssidref)
-        else:
-            label = None
-        return (xsconstants.ACM_POLICY_ID, 'NULL', label)
-
-
-    tmp = get_resource_label(resource)
-    if len(tmp) == 2:
-        policytype = xsconstants.ACM_POLICY_ID
-        policy, label = tmp
-    elif len(tmp) == 3:
-        policytype, policy, label = tmp
-    else:
-        policytype, policy, label = default_res_label()
-
-    return (policytype, label, policy)
-
-
-def get_res_security_details(resource):
-    """Returns the (label, ssidref, policy) associated with a given
-       resource from the global resource label file.
-    """
-    def default_security_details():
-        ssidref = NULL_SSIDREF
-        if on():
-            label = ssidref2label(ssidref)
-        else:
-            label = None
-        policy = active_policy
-        return (label, ssidref, policy)
-
-    (label, ssidref, policy) = default_security_details()
-
-    # find the entry associated with this resource
-    (policytype, label, policy) = get_res_label(resource)
-    if policy == 'NULL':
-        log.info("Resource label for "+resource+" not in file, using DEFAULT.")
-        return default_security_details()
-
-    # is this resource label for the running policy?
-    if policy == active_policy:
-        ssidref = label2ssidref(label, policy, 'res')
-    else:
-        log.info("Resource label not for active policy, using DEFAULT.")
-        return default_security_details()
-
-    return (label, ssidref, policy)
-
-def security_label_to_details(seclab):
-    """ Convert a Xen-API type of security label into details """
-    def default_security_details():
-        ssidref = NULL_SSIDREF
-        if on():
-            label = ssidref2label(ssidref)
-        else:
-            label = None
-        policy = active_policy
-        return (label, ssidref, policy)
-
-    (policytype, policy, label) = seclab.split(":")
-
-    # is this resource label for the running policy?
-    if policy == active_policy:
-        ssidref = label2ssidref(label, policy, 'res')
-    else:
-        log.info("Resource label not for active policy, using DEFAULT.")
-        return default_security_details()
-
-    return (label, ssidref, policy)
-
-def unify_resname(resource, mustexist=True):
-    """Makes all resource locations absolute. In case of physical
-    resources, '/dev/' is added to local file names"""
-
-    if not resource:
-        return resource
-
-    # sanity check on resource name
-    try:
-        (typ, resfile) = resource.split(":", 1)
-    except:
-        err("Resource spec '%s' contains no ':' delimiter" % resource)
-
-    if typ == "tap":
-        try:
-            (subtype, resfile) = resfile.split(":")
-        except:
-            err("Resource spec '%s' contains no tap subtype" % resource)
-
-    import os
-    if typ in ["phy", "tap"]:
-        if not resfile.startswith("/"):
-            resfile = "/dev/" + resfile
-        if mustexist:
-            stats = os.lstat(resfile)
-            if stat.S_ISLNK(stats[stat.ST_MODE]):
-                resolved = os.readlink(resfile)
-                if resolved[0] != "/":
-                    resfile = os.path.join(os.path.dirname(resfile), resolved)
-                    resfile = os.path.abspath(resfile)
-                else:
-                    resfile = resolved
-                stats = os.lstat(resfile)
-            if not (stat.S_ISBLK(stats[stat.ST_MODE])):
-                err("Invalid resource")
-
-    if typ in [ "file", "tap" ]:
-        if mustexist:
-            stats = os.lstat(resfile)
-            if stat.S_ISLNK(stats[stat.ST_MODE]):
-                resfile = os.readlink(resfile)
-                stats = os.lstat(resfile)
-            if not stat.S_ISREG(stats[stat.ST_MODE]):
-                err("Invalid resource")
-
-    #file: resources must specified with absolute path
-    #vlan resources don't start with '/'
-    if typ != "vlan":
-        if (not resfile.startswith("/")) or \
-           (mustexist and not os.path.exists(resfile)):
-            err("Invalid resource.")
-
-    # from here on absolute file names with resources
-    if typ == "tap":
-        typ = typ + ":" + subtype
-    resource = typ + ":" + resfile
-    return resource
-
-
-def res_security_check(resource, domain_label):
-    """Checks if the given resource can be used by the given domain
-       label.  Returns 1 if the resource can be used, otherwise 0.
-    """
-    rtnval = 1
-
-    # if security is on, ask the hypervisor for a decision
-    if on():
-        #build canonical resource name
-        resource = unify_resname(resource)
-
-        (label, ssidref, policy) = get_res_security_details(resource)
-        domac = ['access_control']
-        domac.append(['policy', active_policy])
-        domac.append(['label', domain_label])
-        domac.append(['type', 'dom'])
-        decision = get_decision(domac, ['ssidref', str(ssidref)])
-
-        # provide descriptive error messages
-        if decision == 'DENIED':
-            if label == ssidref2label(NULL_SSIDREF):
-                raise ACMError("Resource '"+resource+"' is not labeled")
-                rtnval = 0
-            else:
-                raise ACMError("Permission denied for resource '"+resource+"' because label '"+label+"' is not allowed")
-                rtnval = 0
-
-    # security is off, make sure resource isn't labeled
-    else:
-        # Note, we can't canonicalise the resource here, because people using
-        # xm without ACM are free to use relative paths.
-        (policytype, label, policy) = get_res_label(resource)
-        if policy != 'NULL':
-            raise ACMError("Security is off, but '"+resource+"' is labeled")
-            rtnval = 0
-
-    return rtnval
-
-def res_security_check_xapi(rlabel, rssidref, rpolicy, xapi_dom_label):
-    """Checks if the given resource can be used by the given domain
-       label.  Returns 1 if the resource can be used, otherwise 0.
-    """
-    rtnval = 1
-    # if security is on, ask the hypervisor for a decision
-    if on():
-        typ, dpolicy, domain_label = xapi_dom_label.split(":")
-        if not dpolicy or not domain_label:
-            raise VmError("VM security label in wrong format.")
-        if active_policy != rpolicy:
-            raise VmError("Resource's policy '%s' != active policy '%s'" %
-                          (rpolicy, active_policy))
-        domac = ['access_control']
-        domac.append(['policy', active_policy])
-        domac.append(['label', domain_label])
-        domac.append(['type', 'dom'])
-        decision = get_decision(domac, ['ssidref', str(rssidref)])
-
-        log.info("Access Control Decision : %s" % decision)
-        # provide descriptive error messages
-        if decision == 'DENIED':
-            if rlabel == ssidref2label(NULL_SSIDREF):
-                #raise ACMError("Resource is not labeled")
-                rtnval = 0
-            else:
-                #raise ACMError("Permission denied for resource because label '"+rlabel+"' is not allowed")
-                rtnval = 0
-
-    # security is off, make sure resource isn't labeled
-    else:
-        # Note, we can't canonicalise the resource here, because people using
-        # xm without ACM are free to use relative paths.
-        if rpolicy != 'NULL':
-            #raise ACMError("Security is off, but resource is labeled")
-            rtnval = 0
-
-    return rtnval
-
-
-def validate_label(label, policyref):
-    """
-       Make sure that this label is part of the currently enforced policy
-       and that it reference the current policy.
-    """
-    rc = xsconstants.XSERR_SUCCESS
-    from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
-    curpol = XSPolicyAdminInstance().get_loaded_policy()
-    if not curpol or curpol.get_name() != policyref:
-        rc = -xsconstants.XSERR_BAD_LABEL
-    else:
-        try:
-            label2ssidref(label, curpol.get_name() , 'res')
-        except:
-            rc = -xsconstants.XSERR_BAD_LABEL
-    return rc
-
-
-def set_resource_label_xapi(resource, reslabel_xapi, oldlabel_xapi):
-    """Assign a resource label to a resource
-    @param resource: The name of a resource, i.e., "phy:/dev/hda", or
-              "tap:qcow:/path/to/file.qcow"
-
-    @param reslabel_xapi: A resource label foramtted as in all other parts of
-                          the Xen-API, i.e., ACM:xm-test:blue"
-    @rtype: int
-    @return Success (0) or failure value (< 0)
-    """
-    olabel = ""
-    if reslabel_xapi == "":
-        return rm_resource_label(resource, oldlabel_xapi)
-    typ, policyref, label = reslabel_xapi.split(":")
-    if typ != xsconstants.ACM_POLICY_ID:
-        return -xsconstants.XSERR_WRONG_POLICY_TYPE
-    if not policyref or not label:
-        return -xsconstants.XSERR_BAD_LABEL_FORMAT
-    if oldlabel_xapi not in [ "" ]:
-        tmp = oldlabel_xapi.split(":")
-        if len(tmp) != 3:
-            return -xsconstants.XSERR_BAD_LABEL_FORMAT
-        otyp, opolicyref, olabel = tmp
-        # Only ACM is supported
-        if otyp != xsconstants.ACM_POLICY_ID  and \
-           otyp != xsconstants.INVALID_POLICY_PREFIX + \
-                   xsconstants.ACM_POLICY_ID:
-            return -xsconstants.XSERR_WRONG_POLICY_TYPE
-    rc = validate_label(label, policyref)
-    if rc != xsconstants.XSERR_SUCCESS:
-        return rc
-    return set_resource_label(resource, typ, policyref, label, olabel)
-
-
-def is_resource_in_use(resource):
-    """
-       Domain-0 'owns' resources of type 'VLAN', the rest are owned by
-       the guests.
-    """
-    from xen.xend import XendDomain
-    lst = []
-    if resource.startswith('vlan'):
-        from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
-        curpol = XSPolicyAdminInstance().get_loaded_policy()
-        policytype, label, policy = get_res_label(resource)
-        if curpol and \
-           policytype == xsconstants.ACM_POLICY_ID and \
-           policy == curpol.get_name() and \
-           label in curpol.policy_get_resourcelabel_names():
-            # VLAN is in use.
-            lst.append(XendDomain.instance().
-                         get_vm_by_uuid(XendDomain.DOM0_UUID))
-    else:
-        dominfos = XendDomain.instance().list('all')
-        for dominfo in dominfos:
-            if is_resource_in_use_by_dom(dominfo, resource):
-                lst.append(dominfo)
-    return lst
-
-def devices_equal(res1, res2, mustexist=True):
-    """ Determine whether two devices are equal """
-    return (unify_resname(res1, mustexist) ==
-            unify_resname(res2, mustexist))
-
-def is_resource_in_use_by_dom(dominfo, resource):
-    """ Determine whether a resources is in use by a given domain
-        @return True or False
-    """
-    if not dominfo.domid:
-        return False
-    if dominfo._stateGet() not in [ DOM_STATE_RUNNING ]:
-        return False
-    devs = dominfo.info['devices']
-    uuids = devs.keys()
-    for uuid in uuids:
-        dev = devs[uuid]
-        if len(dev) >= 2 and dev[1].has_key('uname'):
-            # dev[0] is type, i.e. 'vbd'
-            if devices_equal(dev[1]['uname'], resource, mustexist=False):
-                log.info("RESOURCE IN USE: Domain %d uses %s." %
-                         (dominfo.domid, resource))
-                return True
-    return False
-
-
-def get_domain_resources(dominfo):
-    """ Collect all resources of a domain in a map where each entry of
-        the map is a list.
-        Entries are strored in the following formats:
-          tap:qcow:/path/xyz.qcow
-    """
-    resources = { 'vbd' : [], 'tap' : [], 'vif' : []}
-    devs = dominfo.info['devices']
-    uuids = devs.keys()
-    for uuid in uuids:
-        dev = devs[uuid]
-        typ = dev[0]
-        if typ in [ 'vbd', 'tap' ]:
-            resources[typ].append(dev[1]['uname'])
-        if typ in [ 'vif' ]:
-            sec_lab = dev[1].get('security_label')
-            if sec_lab:
-                resources[typ].append(sec_lab)
-            else:
-                # !!! This should really get the label of the domain
-                # or at least a resource label that has the same STE type
-                # as the domain has
-                from xen.util.acmpolicy import ACM_LABEL_UNLABELED
-                resources[typ].append("%s:%s:%s" %
-                                      (xsconstants.ACM_POLICY_ID,
-                                       active_policy,
-                                       ACM_LABEL_UNLABELED))
-
-    return resources
-
-
-def resources_compatible_with_vmlabel(xspol, dominfo, vmlabel):
-    """
-       Check whether the resources' labels are compatible with the
-       given VM label. This is a function to be used when for example
-       a running domain is to get the new label 'vmlabel'
-    """
-    if not xspol:
-        return False
-
-    try:
-        __resfile_lock.acquire()
-        try:
-            access_control = dictio.dict_read("resources",
-                                              res_label_filename)
-        except:
-            # No labeled resources -> must be compatible
-            return True
-        return __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel,
-                                                   access_control)
-    finally:
-        __resfile_lock.release()
-    return False
-
-
-def __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel,
-                                        access_control,
-                                        is_policy_update=False):
-    """
-        Check whether the resources' labels are compatible with the
-        given VM label. The access_control parameter provides a
-        dictionary of the resource name to resource label mappings
-        under which the evaluation should be done.
-        Call this only for a paused or running domain.
-    """
-    def collect_labels(reslabels, s_label, polname):
-        if len(s_label) != 3 or polname != s_label[1]:
-            return False
-        label = s_label[2]
-        if not label in reslabels:
-            reslabels.append(label)
-        return True
-
-    resources = get_domain_resources(dominfo)
-    reslabels = []  # all resource labels
-
-    polname = xspol.get_name()
-    for key, value in resources.items():
-        if key in [ 'vbd', 'tap' ]:
-            for res in resources[key]:
-                try:
-                    label = access_control[res]
-                    if not collect_labels(reslabels, label, polname):
-                        return False
-                except:
-                    return False
-        elif key in [ 'vif' ]:
-            for xapi_label in value:
-                label = xapi_label.split(":")
-                from xen.util.acmpolicy import ACM_LABEL_UNLABELED
-                if not (is_policy_update and \
-                        label[2] == ACM_LABEL_UNLABELED):
-                    if not collect_labels(reslabels, label, polname):
-                        return False
-        else:
-            log.error("Unhandled device type: %s" % key)
-            return False
-
-    # Check that all resource labes have a common STE type with the
-    # vmlabel
-    if len(reslabels) > 0:
-        rc = xspol.policy_check_vmlabel_against_reslabels(vmlabel, reslabels)
-    else:
-        rc = True
-    log.info("vmlabel=%s, reslabels=%s, rc=%s" %
-             (vmlabel, reslabels, str(rc)))
-    return rc;
-
-def set_resource_label(resource, policytype, policyref, reslabel, \
-                       oreslabel = None):
-    """Assign a label to a resource
-       If the old label (oreslabel) is given, then the resource must have
-       that old label.
-       A resource label may be changed if
-       - the resource is not in use
-    @param resource  : The name of a resource, i.e., "phy:/dev/hda"
-    @param policyref : The name of the policy
-    @param reslabel     : the resource label within the policy
-    @param oreslabel    : optional current resource label
-
-    @rtype: int
-    @return Success (0) or failure value (< 0)
-    """
-    try:
-        resource = unify_resname(resource, mustexist=False)
-    except Exception:
-        return -xsconstants.XSERR_BAD_RESOURCE_FORMAT
-
-    domains = is_resource_in_use(resource)
-    if len(domains) > 0:
-        return -xsconstants.XSERR_RESOURCE_IN_USE
-
-    try:
-        __resfile_lock.acquire()
-        access_control = {}
-        try:
-             access_control = dictio.dict_read("resources", res_label_filename)
-        except:
-            pass
-        if oreslabel:
-            if not access_control.has_key(resource):
-                return -xsconstants.XSERR_BAD_LABEL
-            tmp = access_control[resource]
-            if len(tmp) != 3:
-                return -xsconstants.XSERR_BAD_LABEL
-            if tmp[2] != oreslabel:
-                return -xsconstants.XSERR_BAD_LABEL
-        if reslabel != "":
-            new_entry = { resource : tuple([policytype, policyref, reslabel])}
-            access_control.update(new_entry)
-        else:
-            if access_control.has_key(resource):
-                del access_control[resource]
-        dictio.dict_write(access_control, "resources", res_label_filename)
-    finally:
-        __resfile_lock.release()
-    return xsconstants.XSERR_SUCCESS
-
-def rm_resource_label(resource, oldlabel_xapi):
-    """Remove a resource label from a physical resource
-    @param resource: The name of a resource, i.e., "phy:/dev/hda"
-
-    @rtype: int
-    @return Success (0) or failure value (< 0)
-    """
-    tmp = oldlabel_xapi.split(":")
-    if len(tmp) != 3:
-        return -xsconstants.XSERR_BAD_LABEL_FORMAT
-    otyp, opolicyref, olabel = tmp
-    # Only ACM is supported
-    if otyp != xsconstants.ACM_POLICY_ID and \
-       otyp != xsconstants.INVALID_POLICY_PREFIX + xsconstants.ACM_POLICY_ID:
-        return -xsconstants.XSERR_WRONG_POLICY_TYPE
-    return set_resource_label(resource, "", "", "", olabel)
-
-def get_resource_label_xapi(resource):
-    """Get the assigned resource label of a physical resource
-      in the format used by then Xen-API, i.e., "ACM:xm-test:blue"
-
-      @rtype: string
-      @return the string representing policy type, policy name and label of
-              the resource
-    """
-    res = get_resource_label(resource)
-    return format_resource_label(res)
-
-def format_resource_label(res):
-    if res:
-        if len(res) == 2:
-            return xsconstants.ACM_POLICY_ID + ":" + res[0] + ":" + res[1]
-        if len(res) == 3:
-            return ":".join(res)
-    return ""
-
-def get_resource_label(resource):
-    """Get the assigned resource label of a given resource
-    @param resource: The name of a resource, i.e., "phy:/dev/hda"
-
-    @rtype: list
-    @return tuple of (policy name, resource label), i.e., (xm-test, blue)
-    """
-    try:
-        resource = unify_resname(resource, mustexist=False)
-    except Exception:
-        return []
-
-    reslabel_map = get_labeled_resources()
-
-    if reslabel_map.has_key(resource):
-        return list(reslabel_map[resource])
-    else:
-        #Try to resolve each label entry
-        for key, value in reslabel_map.items():
-            try:
-                if resource == unify_resname(key):
-                    return list(value)
-            except:
-                pass
-
-    return []
-
-
-def get_labeled_resources_xapi():
-    """ Get a map of all labeled resource with the labels formatted in the
-        xen-api resource label format.
-    """
-    reslabel_map = get_labeled_resources()
-    for key, labeldata in reslabel_map.items():
-        reslabel_map[key] = format_resource_label(labeldata)
-    return reslabel_map
-
-
-def get_labeled_resources():
-    """Get a map of all labeled resources
-    @rtype: list
-    @return list of labeled resources
-    """
-    try:
-        __resfile_lock.acquire()
-        try:
-            access_control = dictio.dict_read("resources", res_label_filename)
-        except:
-            return {}
-    finally:
-        __resfile_lock.release()
-    return access_control
-
-
-def relabel_domains(relabel_list):
-    """
-      Relabel the given domains to have a new ssidref.
-      @param relabel_list: a list containing tuples of domid, ssidref
-                           example: [ [0, 0x00020002] ]
-    """
-    rel_rules = ""
-    for r in relabel_list:
-        log.info("Relabeling domain with domid %d to new ssidref 0x%08x",
-                r[0], r[1])
-        rel_rules += struct.pack("ii", r[0], r[1])
-    try:
-        rc, errors = acm.relabel_domains(rel_rules)
-    except Exception, e:
-        log.info("Error after relabel_domains: %s" % str(e))
-        rc = -xsconstants.XSERR_GENERAL_FAILURE
-        errors = ""
-    if (len(errors) > 0):
-        rc = -xsconstants.XSERR_HV_OP_FAILED
-    return rc, errors
-
-
-def change_acm_policy(bin_pol, del_array, chg_array,
-                      vmlabel_map, reslabel_map, cur_acmpol, new_acmpol):
-    """
-       Change the ACM policy of the system by relabeling
-       domains and resources first and doing some access checks.
-       Then update the policy in the hypervisor. If this is all successful,
-       relabel the domains permanently and commit the relabed resources.
-
-       Need to do / check the following:
-        - relabel all resources where there is a 'from' field in
-          the policy. [ NOT DOING THIS: and mark those as unlabeled where the label
-          does not appear in the new policy anymore (deletion) ]
-        - relabel all VMs where there is a 'from' field in the
-          policy and mark those as unlabeled where the label
-          does not appear in the new policy anymore; no running
-          or paused VM may be unlabeled through this
-        - check that under the new labeling conditions the VMs
-          still have access to their resources as before. Unlabeled
-          resources are inaccessible. If this check fails, the
-          update failed.
-        - Attempt changes in the hypervisor; if this step fails,
-          roll back the relabeling of resources and VMs
-        - Make the relabeling of resources and VMs permanent
-    """
-    rc = xsconstants.XSERR_SUCCESS
-
-    domain_label_map = {}
-    new_policyname = new_acmpol.get_name()
-    new_policytype = new_acmpol.get_type_name()
-    cur_policyname = cur_acmpol.get_name()
-    cur_policytype = cur_acmpol.get_type_name()
-    polnew_reslabels = new_acmpol.policy_get_resourcelabel_names()
-    errors=""
-
-    try:
-        __resfile_lock.acquire()
-        mapfile_lock()
-
-        # Get all domains' dominfo.
-        from xen.xend import XendDomain
-        dominfos = XendDomain.instance().list('all')
-
-        log.info("----------------------------------------------")
-        # relabel resources
-
-        access_control = {}
-        try:
-            access_control = dictio.dict_read("resources", res_label_filename)
-        except:
-            pass
-        for key, labeldata in access_control.items():
-            if len(labeldata) == 2:
-                policy, label = labeldata
-                policytype = xsconstants.ACM_POLICY_ID
-            elif len(labeldata) == 3:
-                policytype, policy, label = labeldata
-            else:
-                return -xsconstants.XSERR_BAD_LABEL_FORMAT, ""
-
-            if policytype != cur_policytype or \
-               policy     != cur_policyname:
-                continue
-
-            # label been renamed or deleted?
-            if reslabel_map.has_key(label) and cur_policyname == policy:
-                label = reslabel_map[label]
-            elif label not in polnew_reslabels:
-                policytype = xsconstants.INVALID_POLICY_PREFIX + policytype
-            # Update entry
-            access_control[key] = \
-                   tuple([ policytype, new_policyname, label ])
-
-        # All resources have new labels in the access_control map
-        # There may still be labels in there that are invalid now.
-
-        # Do this in memory without writing to disk:
-        #  - Relabel all domains independent of whether they are running
-        #    or not
-        #  - later write back to config files
-        polnew_vmlabels = new_acmpol.policy_get_virtualmachinelabel_names()
-
-        for dominfo in dominfos:
-            sec_lab = dominfo.get_security_label()
-            if not sec_lab:
-                continue
-            policytype, policy, vmlabel = sec_lab.split(":")
-            name  = dominfo.getName()
-
-            if policytype != cur_policytype or \
-               policy     != cur_policyname:
-                continue
-
-            new_vmlabel = vmlabel
-            if vmlabel_map.has_key(vmlabel):
-                new_vmlabel = vmlabel_map[vmlabel]
-            if new_vmlabel not in polnew_vmlabels:
-                policytype = xsconstants.INVALID_POLICY_PREFIX + policytype
-            new_seclab = "%s:%s:%s" % \
-                    (policytype, new_policyname, new_vmlabel)
-
-            domain_label_map[dominfo] = [ sec_lab, new_seclab ]
-
-            if dominfo._stateGet() in (DOM_STATE_PAUSED, DOM_STATE_RUNNING):
-                compatible = __resources_compatible_with_vmlabel(new_acmpol,
-                                                      dominfo,
-                                                      new_vmlabel,
-                                                      access_control,
-                                                      is_policy_update=True)
-                log.info("Domain %s with new label '%s' can access its "
-                         "resources? : %s" %
-                         (name, new_vmlabel, str(compatible)))
-                log.info("VM labels in new policy: %s" %
-                         new_acmpol.policy_get_virtualmachinelabel_names())
-                if not compatible:
-                    return (-xsconstants.XSERR_RESOURCE_ACCESS, "")
-
-        rc, errors = hv_chg_policy(bin_pol, del_array, chg_array)
-        if rc == 0:
-            # Write the relabeled resources back into the file
-            dictio.dict_write(access_control, "resources", res_label_filename)
-            # Properly update all VMs to their new labels
-            for dominfo, labels in domain_label_map.items():
-                sec_lab, new_seclab = labels
-                if sec_lab != new_seclab:
-                    log.info("Updating domain %s to new label '%s'." % \
-                             (dominfo.getName(), new_seclab))
-                    # This better be working!
-                    res = dominfo.set_security_label(new_seclab,
-                                                     sec_lab,
-                                                     new_acmpol,
-                                                     cur_acmpol)
-                    if res[0] != xsconstants.XSERR_SUCCESS:
-                        log.info("ERROR: Could not chg label on domain %s: %s" %
-                                 (dominfo.getName(),
-                                  xsconstants.xserr2string(-int(res[0]))))
-    finally:
-        log.info("----------------------------------------------")
-        mapfile_unlock()
-        __resfile_lock.release()
-
-    return rc, errors
index 6102e6f8993a1deb62b39556919077f61c00711c..b2dff14edd5fd8e2d97808736108c5041a61a332 100644 (file)
@@ -838,13 +838,28 @@ def set_resource_label_xapi(resource, reslabel_xapi, oldlabel_xapi):
 
 
 def is_resource_in_use(resource):
-    """ Investigate all running domains whether they use this device """
+    """
+       Domain-0 'owns' resources of type 'VLAN', the rest are owned by
+       the guests.
+    """
     from xen.xend import XendDomain
-    dominfos = XendDomain.instance().list('all')
     lst = []
-    for dominfo in dominfos:
-        if is_resource_in_use_by_dom(dominfo, resource):
-            lst.append(dominfo)
+    if resource.startswith('vlan'):
+        from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
+        curpol = XSPolicyAdminInstance().get_loaded_policy()
+        policytype, label, policy = get_res_label(resource)
+        if curpol and \
+           policytype == xsconstants.ACM_POLICY_ID and \
+           policy == curpol.get_name() and \
+           label in curpol.policy_get_resourcelabel_names():
+            # VLAN is in use.
+            lst.append(XendDomain.instance().
+                         get_vm_by_uuid(XendDomain.DOM0_UUID))
+    else:
+        dominfos = XendDomain.instance().list('all')
+        for dominfo in dominfos:
+            if is_resource_in_use_by_dom(dominfo, resource):
+                lst.append(dominfo)
     return lst
 
 def devices_equal(res1, res2, mustexist=True):
@@ -892,6 +907,10 @@ def get_domain_resources(dominfo):
             if sec_lab:
                 resources[typ].append(sec_lab)
             else:
+                # !!! This should really get the label of the domain
+                # or at least a resource label that has the same STE type
+                # as the domain has
+                from xen.util.acmpolicy import ACM_LABEL_UNLABELED
                 resources[typ].append("%s:%s:%s" %
                                       (xsconstants.ACM_POLICY_ID,
                                        active_policy,
@@ -915,7 +934,8 @@ def resources_compatible_with_vmlabel(xspol, dominfo, vmlabel):
             access_control = dictio.dict_read("resources",
                                               res_label_filename)
         except:
-            return False
+            # No labeled resources -> must be compatible
+            return True
         return __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel,
                                                    access_control)
     finally:
@@ -924,12 +944,14 @@ def resources_compatible_with_vmlabel(xspol, dominfo, vmlabel):
 
 
 def __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel,
-                                        access_control):
+                                        access_control,
+                                        is_policy_update=False):
     """
         Check whether the resources' labels are compatible with the
         given VM label. The access_control parameter provides a
         dictionary of the resource name to resource label mappings
         under which the evaluation should be done.
+        Call this only for a paused or running domain.
     """
     def collect_labels(reslabels, s_label, polname):
         if len(s_label) != 3 or polname != s_label[1]:
@@ -955,15 +977,23 @@ def __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel,
         elif key in [ 'vif' ]:
             for xapi_label in value:
                 label = xapi_label.split(":")
-                if not collect_labels(reslabels, label, polname):
-                    return False
+                from xen.util.acmpolicy import ACM_LABEL_UNLABELED
+                if not (is_policy_update and \
+                        label[2] == ACM_LABEL_UNLABELED):
+                    if not collect_labels(reslabels, label, polname):
+                        return False
         else:
             log.error("Unhandled device type: %s" % key)
             return False
 
     # Check that all resource labes have a common STE type with the
     # vmlabel
-    rc = xspol.policy_check_vmlabel_against_reslabels(vmlabel, reslabels)
+    if len(reslabels) > 0:
+        rc = xspol.policy_check_vmlabel_against_reslabels(vmlabel, reslabels)
+    else:
+        rc = True
+    log.info("vmlabel=%s, reslabels=%s, rc=%s" %
+             (vmlabel, reslabels, str(rc)))
     return rc;
 
 def set_resource_label(resource, policytype, policyref, reslabel, \
@@ -1176,7 +1206,7 @@ def change_acm_policy(bin_pol, del_array, chg_array,
         access_control = {}
         try:
             access_control = dictio.dict_read("resources", res_label_filename)
-        finally:
+        except:
             pass
         for key, labeldata in access_control.items():
             if len(labeldata) == 2:
@@ -1234,11 +1264,12 @@ def change_acm_policy(bin_pol, del_array, chg_array,
                 compatible = __resources_compatible_with_vmlabel(new_acmpol,
                                                       dominfo,
                                                       new_vmlabel,
-                                                      access_control)
+                                                      access_control,
+                                                      is_policy_update=True)
                 log.info("Domain %s with new label '%s' can access its "
                          "resources? : %s" %
                          (name, new_vmlabel, str(compatible)))
-                log.info("VM labels in new domain: %s" %
+                log.info("VM labels in new policy: %s" %
                          new_acmpol.policy_get_virtualmachinelabel_names())
                 if not compatible:
                     return (-xsconstants.XSERR_RESOURCE_ACCESS, "")
@@ -1252,11 +1283,16 @@ def change_acm_policy(bin_pol, del_array, chg_array,
                 sec_lab, new_seclab = labels
                 if sec_lab != new_seclab:
                     log.info("Updating domain %s to new label '%s'." % \
-                             (sec_lab, new_seclab))
+                             (dominfo.getName(), new_seclab))
                     # This better be working!
-                    dominfo.set_security_label(new_seclab,
-                                               sec_lab,
-                                               new_acmpol)
+                    res = dominfo.set_security_label(new_seclab,
+                                                     sec_lab,
+                                                     new_acmpol,
+                                                     cur_acmpol)
+                    if res[0] != xsconstants.XSERR_SUCCESS:
+                        log.info("ERROR: Could not chg label on domain %s: %s" %
+                                 (dominfo.getName(),
+                                  xsconstants.xserr2string(-int(res[0]))))
     finally:
         log.info("----------------------------------------------")
         mapfile_unlock()